#include "myheadd.h"


char *get_name(char *filepath) 
{
    char *filename = strrchr(filepath, '/');//查找最后一个'/'字符
    return (filename == NULL) ? filepath : filename + 1;//返回文件名的部分
}


void *file_recv_handler(void *arg) 
{
    int connfd = (intptr_t)arg;
    char buf[1024] = {0};      //数据缓冲区
    char filename[100] = {0};  //文件名
    long filesize = 0;         //文件大小
    char str[100] = {0};        //接收文件信息的缓冲区
    int select = 0;             //用户选择

    
    if (recv(connfd, str, sizeof(str), 0) <= 0) // 接收文件名和大小
    {
        perror("接收文件信息失败");
        close(connfd);
        return NULL;
    }
    sscanf(str, "%s %ld", filename, &filesize);

    
    printf("\n收到文件: %s (大小: %ld字节)，是否接收？(多次输入回车+9:接收 :其他数字拒绝)\n", filename, filesize);// 询问用户是否接收
    scanf("%d", &select);
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
    send(connfd, &select, sizeof(select), 0); // 发送确认结果
    if (select != 9) 
    {
        printf("已拒绝接收文件\n");
        close(connfd);
        return NULL;
    }

    
    if (access("Download", F_OK) != 0) // 创建Download目录（若不存在）
    {
        if (mkdir("Download", 0755) < 0) 
        {
            perror("创建Download目录失败");
            close(connfd);
            return NULL;
        }
    }

    
    char filepath[200] = {0}; // 保存文件
    sprintf(filepath, "Download/%s", filename); // 构建完整的保存路径
    int file_fd = open(filepath, O_CREAT | O_TRUNC | O_WRONLY, 0644);
    if (file_fd < 0) 
    {
        perror("创建文件失败");
        close(connfd);
        return NULL;
    }

    
    long recv_size = 0;// 接收文件内容
    int n;
    while (recv_size < filesize) 
    {
        n = recv(connfd, buf, sizeof(buf), 0);//每次就1kb1kb的传输
        if (n <= 0) 
            break;
        write(file_fd, buf, n);
        recv_size += n;
    }

    // 传输结果判断
    if (recv_size == filesize) 
    {
        printf("文件接收完成，保存至: %s\n", filepath);
    } 
    else 
    {
        printf("文件接收中断，已删除不完整文件\n");
        unlink(filepath);//删除文件
    }

    close(file_fd);
    close(connfd);
    return NULL;
}




void *file_transfer_listener(void *arg) // 文件传输监听线程（t4线程函数，完全独立）
{
    char *my_name = (char *)arg;
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0) 
    {
        perror("创建文件监听套接字失败");
        return NULL;
    }

    // 设置端口复用
    int reuse = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

    // 绑定独立的文件传输端口（不与私聊端口冲突）
    struct sockaddr_in my_addr;
    memset(&my_addr, 0, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(my_file_port);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(listenfd, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) 
    {
        perror("绑定文件传输端口失败");
        close(listenfd);
        return NULL;
    }

    listen(listenfd, 5);
    printf("文件传输监听已启动，端口: %d（独立端口，不影响私聊）\n", my_file_port);

    // 循环接收连接（独立处理，不影响原有私聊）
    struct sockaddr_in client_addr;
    socklen_t len = sizeof(client_addr);
    while (1) 
    {
        int connfd = accept(listenfd, (struct sockaddr *)&client_addr, &len);
        if (connfd < 0) 
        {
            perror("接收文件连接失败");
            continue;
        }

        // 创建独立线程处理文件接收
        pthread_t tid;
        if (pthread_create(&tid, NULL, file_recv_handler, (void *)(intptr_t)connfd) != 0) 
        {
            perror("创建文件接收线程失败");
            close(connfd);
        }
        pthread_detach(tid);//分离线程，自动回收资源，相当于把指定线程标记为“分离状态”，就不用调用pthread_joinl了;
    }

    close(listenfd);
    return NULL;
}

// 发起文件传输（完全独立的函数，不调用原有私聊逻辑）
void start_file_transfer(char *friend_name, char *filepath) 
{
    // 参数校验
    if (!friend_name || !filepath || access(filepath, F_OK) != 0) 
    {
        printf("无效的好友名或文件不存在\n");
        return;
    }

    
    pthread_mutex_lock(&list_mutex);// 查找好友信息（使用互斥锁保护共享列表）
    Friend *target = NULL;
    bool found = false;
    list_for_each_entry(target, &friend_list->list, list) 
    {
        if (strcmp(target->user_name, friend_name) == 0 && target->is_offline == 0) 
        {
            found = true;
            break;
        }
    }
    if (!found) 
    {
        printf("好友不在线或不存在\n");
        pthread_mutex_unlock(&list_mutex);
        return;
    }

    
    char target_ip[16];// 保存目标信息（解锁前）
    unsigned short target_port = target->file_port; // 使用独立的文件端口
    strncpy(target_ip, target->ip, sizeof(target_ip)-1);
    pthread_mutex_unlock(&list_mutex);

 
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
    {
        perror("创建传输套接字失败");
        return;
    }

    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(target_port);
    dest_addr.sin_addr.s_addr = inet_addr(target_ip);

    if (connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0) 
    {
        perror("连接好友文件端口失败");
        close(sockfd);
        return;
    }

    // 发送文件信息
    char *filename = get_name(filepath);
    struct stat info;
    stat(filepath, &info);
    long filesize = info.st_size;
    char str[100] = {0};
    sprintf(str, "%s %ld", filename, filesize);
    send(sockfd, str, strlen(str), 0);

    // 等待对方确认
    int select;
    recv(sockfd, &select, sizeof(select), 0);
    if (select != 9)
    {
        printf("对方拒绝接收文件\n");
        close(sockfd);
        return;
    }

    // 发送文件内容
    int file_fd = open(filepath, O_RDONLY);
    if (file_fd < 0) 
    {
        perror("打开文件失败");
        close(sockfd);
        return;
    }

    char buf[1024];
    int n;
    printf("开始发送文件...\n");
    while ((n = read(file_fd, buf, sizeof(buf))) > 0) 
    {
        send(sockfd, buf, n, 0);
    }
    printf("文件发送完成\n");

    close(file_fd);
    close(sockfd);
}
    